#ifndef DATAINPUTMODELPARTGENERATOR_H_JM_20130219
#define DATAINPUTMODELPARTGENERATOR_H_JM_20130219
/// @file DataInputModelPartGenerator.h
/// Generator casti modelu - spustenie vypoctu + vstup dat do vypoctu.
#include "../generators/ModelGenerator.h"
#include "../generators/Slices.h"
#include "InputBoxConfiguration.h"

namespace jm4bbx {

	/// Generator casti modelu - spustenie vypoctu + vstup dat do vypoctu.
	class  DataInputModelPartGenerator {
	public:

		/// Prida potrebne boxy do generatoru modelu.
		/// @param mg generator modelu, ktoremu sa pridavaju boxy pre nacitanie 
		/// dat
		/// @param inputBoxName meno vstupnych boxov, kt. sa pridavaju
		/// @param inputConfs pole konfiguracii vstupnych boxov
		/// @param inputCount pocet konfiguracii v poli (urcuje pocet vstupnych 
		/// boxov resp. stupen paralelizacie)
		void addBoxes(ModelGenerator* mg, const std::string& inputBoxName, 
			InputBoxConfiguration* inputConfs, 
			int inputCount, int forkParallelism, 
			bool startDataForkSinalFirst /*= true*/,
			bool allDataForkHasOneInputSinals) {
			
			startDataForkSinalFirst_ = startDataForkSinalFirst;
			allDataForkHasOneInputSinals_ = allDataForkHasOneInputSinals;
			startForkBox_ = mg->addBox("SIGNAL_FORK",
				genBoxParam("signal_out", inputCount));


			for (size_t i = 0; i < inputCount; ++i) {
				inputBoxes_.push_back(mg->addBox(inputBoxName, 
					genBoxParam("specification", inputConfs[i].specification) + 
					genBoxParam("signal_in", 1) + 
					genBoxParam("signal_out", 1) +
					genBoxParam("key_column", inputConfs[i].keyColumnIndex) +
					genBoxParam("first_op_arg", i == 0 ? 1 : 0) ));

				bool hasOneSig = (i == 0) || allDataForkHasOneInputSinals_;

				forkDataBoxes_.push_back(mg->addBox("Fork", 
					genBoxParam("forkFactor", forkParallelism) + 
					genBoxParam("signal_in", hasOneSig ? 1 : forkParallelism)));
				
			}

			timerStartBox_ = mg->addBox("START_TIMER", 
				genBoxParam("signal_in", inputCount) + 
				genBoxParam("signal_out", startDataForkSinalFirst ? 1 : inputCount));
		}


		/// Pridanie rezov do generatoru modelu, kde rezy urcujucich spojenia 
		/// boxov pre nacitanie vstupnych dat.
		/// @param mg generator modelu, ktoremu sa pridavaju rezy spojeni
		/// @param typeName meno typu dat, ktore sa posielaju skrz spojenia
		void addSlices(ModelGenerator* mg, const std::string& typeName) {

			mg->addSlice(new PlainSlice(mg->getModelInputId(), 
				startForkBox_->getBoxId(), D_O, S_I));

			assert(inputBoxes_.size() == forkDataBoxes_.size());

			for (size_t i = 0; i < inputBoxes_.size(); ++i) {
				mg->addSlice(new PlainSlice(startForkBox_->getBoxId(), 
					inputBoxes_[i]->getBoxId(), S_O + i, S_I));

				mg->addSlice(new PlainSlice(inputBoxes_[i]->getBoxId(), 
					timerStartBox_->getBoxId(), S_O, S_I + i));

				mg->addSlice(new PlainSlice(inputBoxes_[i]->getBoxId(), 
					forkDataBoxes_[i]->getBoxId(), D_O, D_I, 
					genTypes(typeName, 1)));	
			}
			
			size_t startSignalCount = startDataForkSinalFirst_ ? 1 : inputBoxes_.size();
			for (size_t i = 0; i < startSignalCount; ++i) {
				mg->addSlice(new PlainSlice(timerStartBox_->getBoxId(), 
					forkDataBoxes_[i]->getBoxId(), S_O + i, S_I));
			}
		}

		/// Spristupnenie boxu, ktory spusta timer.
		BoxDescriptorPtr getTimerStartBox() { return timerStartBox_; }
		/// Spristupnenie  i-teho boxu pre nacitanie dat.
		//BoxDescriptorPtr getInputBox(size_t i) { return inputBoxes_[i]; }
		/// Spristupnenie  i-teho boxu pre vetvenie dat nacitanych i-tym 
		/// vstupnym boxom.
		BoxDescriptorPtr getForkDataBox(size_t i) { return forkDataBoxes_[i]; }
	private:
		/// Boxy nacitajuce data do modelu
		std::vector<BoxDescriptorPtr> inputBoxes_;
		/// Boxy deliace data po vstupe do modelu pre paralelne spracovanie
		std::vector<BoxDescriptorPtr> forkDataBoxes_;
		/// Signalovy fork pre paralelizaciu nacitania dat.
		BoxDescriptorPtr startForkBox_;
		/// Spustac timeru
		BoxDescriptorPtr timerStartBox_;
		/// Startujuci signal z timeru do prveho dataforku? 
		/// Pokial nie tak potom do vsetkych dataforkov.
		bool startDataForkSinalFirst_;
		bool allDataForkHasOneInputSinals_;
	};

} // namespace jm4bbx


#endif
